1 Tekrarlanabilir Analiz ve Rapor


1.2 Replication Crisis Excel Version


2 RStudio ile proje oluştur


3 R Notebook

3.1 R Notebook dökümanı oluşturma


3.2 R Notebook’tan html, pdf ve word oluşturma


3.3 RNotebook vs RMarkdown

https://youtu.be/zNzZ1PfUDNk


4 R Markdown

4.1 Hem kendi kodları hem de html kodları yazılabilir

https://rmarkdown.rstudio.com

What is R Markdown? from RStudio, Inc. on Vimeo.


4.2 R Markdown: The Definitive Guide

https://bookdown.org/yihui/rmarkdown/


4.3 R Markdown syntax

https://gist.github.com/MinhasKamal/7fdebb7c424d23149140


4.4 Remedy Package


4.4.1 Remedy


4.6 Render Markdown via code

inside R

markdown::markdownToHTML('markdown_example.md', 
'markdown_example.html')

command line

R -e "markdown::markdownToHTML('markdown_example.md',
'markdown_example.html')"

4.7 pandoc Rstudio integration

command line

export PATH=$PATH:/Applications/RStudio.app/Contents/MacOS/pandoc
R -e "rmarkdown::render('markdown_example.md')"

5 RMarkdown chunk içinde R kodlarını çalıştırma

{r, results='asis'}
 iris %>%
  tibble::as_tibble() %>%
  details::details(summary = 'tibble')

6 Metin arasında R kodlarını çalıştırma


7 Chunk Options

7.1 Global Options

{r global_options, include=FALSE}
knitr::opts_chunk$set(fig.width = 12,
                      fig.height = 8,
                      fig.path = 'Figs/',
                      echo = FALSE,
                      warning = FALSE,
                      message = FALSE,
                      error = FALSE,
                      eval = TRUE,
                      tidy = TRUE,
                      comment = NA)

7.2 Other Code Languages


8 R Markdown kod örneği

{r}
data("cancer")
cancer
foreign::write.foreign(df = cancer,
                        datafile = "data/cancer.sav",
                        codefile = "data/cancer.spo",
                        package = "SPSS"
                        )

9 R Markdown Paket Çağırma 📦

{r}
suppressPackageStartupMessages(library("tidyverse"))
suppressPackageStartupMessages(library("survival"))

9.1 Sık kullandığım paketler 📦

{tidyverse} {tidylog}

{lubridate} {janitor}

{readxl} {foreign}

{summarytools} {ggstatsplot} {tangram} {finalfit} {psycho} {jmv}

{survival} {survminer}

{report} {kableExtra}


10 R Markdown Veri Yükleme SPSS


11 R Markdown Veri Yükleme Excel


12 Veri Görüntüleme

{r}
View(mydata)
glimpse(mydata)

13 Veri Düzenleme

{r}
mydata <- janitor::clean_names(mydata)
{r}
mydata$sontarih <- janitor::excel_numeric_to_date(
  as.numeric(mydata$olum_tarihi)
  )

14 Recode

{r}
mydata$Outcome <- "Dead"
mydata$Outcome[mydata$olum_tarihi == "yok"] <- "Alive"
{r}
## Recoding mydata$cinsiyet into mydata$Cinsiyet
mydata$Cinsiyet <- recode(mydata$cinsiyet,
               "K" = "Kadin",
               "E" = "Erkek")
mydata$Cinsiyet <- factor(mydata$Cinsiyet)

15 Recode regular expression

{r recode TNM stage}
#pT2N0Mx -> 2
mydata$Tstage <- stringr::str_match(
  mydata$patolojik_evre, 
  paste('(.+)', "N", sep=''))[,2]
)

16 Recode regular expression case_when

{r recode TNM2}
mydata <- mydata %>% 
    mutate(
        T_stage = case_when(
            grepl(pattern = "T1", x = .$Tstage) == TRUE ~ "T1",
            grepl(pattern = "T2", x = .$Tstage) == TRUE ~ "T2",
            grepl(pattern = "T3", x = .$Tstage) == TRUE ~ "T3",
            grepl(pattern = "T4", x = .$Tstage) == TRUE ~ "T4",
            TRUE ~ "Tx"
        )
    )

17 Recode regular expression case_when

{r}
mydata <- mydata %>% 
    mutate(
TumorPDL1gr1 = case_when(
        t_pdl1 < 1 ~ "kucuk1",
        t_pdl1 >= 1 ~ "buyukesit1"
    )
    )

18 R Markdown Tanımlayıcı İstatistikler

{r}
library(summarytools)
view(dfSummary(colon_s))

A beginner kit for #rstats The Landscape of R Packages for Automated Exploratory Data Analysis https://journal.r-project.org/archive/2019/RJ-2019-033/

@article{RJ-2019-033, author = {Mateusz Staniak and Przemysław Biecek}, title = {{The Landscape of R Packages for Automated Exploratory Data Analysis}}, year = {2019}, journal = {{The R Journal}}, doi = {10.32614/RJ-2019-033}, url = {https://journal.r-project.org/archive/2019/RJ-2019-033/index.html} }


18.1 Table One

{r, results='asis'}
# cat(names(mydata), sep = " + \n")
library(arsenal)
tab1 <- tableby(~ Cinsiyet + 
Yas + 
TumorYerlesimi
                ,
                data = mydata)
summary(tab1)

18.3 Kategorik Veriler

{r}
mydata %>% 
  janitor::tabyl(Categorical) %>%
  adorn_pct_formatting(rounding = 'half up',
                       digits = 1) %>%
  knitr::kable()
{r crosstable}
mydata %>%
    summary_factorlist(dependent = dependent, 
                       explanatory = explanatory,
                       total_col = TRUE,
                       p = TRUE,
                       add_dependent_label = TRUE) -> table
knitr::kable(table, row.names = FALSE, align = c('l', 'l', 'r', 'r', 'r'))

18.4 Kategorik Veriler için Grafikler

{r ggstatplot, layout='l-page'}
mydata %>% 
    ggstatsplot::ggbarstats(data = .,
                            main = Categorical_variable,
                            condition =  dependent_variable
                            )

18.5 Continious Variables

{r}
mydata %>% 
jmv::descriptives(
    data = .,
    vars = c(yas),
    hist = TRUE,
    dens = TRUE,
    box = TRUE,
    violin = TRUE,
    dot = TRUE,
    mode = TRUE,
    sd = TRUE,
    variance = TRUE,
    skew = TRUE,
    kurt = TRUE,
    quart = TRUE)

19 R Markdown örneği Çapraz Tablolar

{r crosstable}
library(finalfit)
mydata %>%
    summary_factorlist(dependent = dependent, 
                       explanatory = explanatory,
                       column = TRUE,
                       total_col = TRUE,
                       p = TRUE,
                       add_dependent_label = TRUE,
                       na_include=FALSE
                       # catTest = catTestfisher
                       ) -> table
knitr::kable(table,
             row.names = FALSE,
             align = c('l', 'l', 'r', 'r', 'r'))

20 R Markdown örneği Sağkalım

20.1 Sağkalım için veriyi düzenleme

{r define survival time}
mydata$int <- lubridate::interval(
  lubridate::ymd(mydata$CerrahiTarih),
  lubridate::ymd(mydata$SonTarih)
  )
mydata$OverallTime <- lubridate::time_length(mydata$int, "month")
mydata$OverallTime <- round(mydata$OverallTime, digits = 1)
{r}
## Recoding mydata$Outcome into mydata$Outcome2
mydata$Outcome2 <- recode(mydata$Outcome,
               "Alive" = "0",
               "Dead" = "1")
mydata$Outcome2 <- as.numeric(mydata$Outcome2)

20.2 Kaplan-Meier

{r Kaplan-Meier}
mydata %>%
  finalfit::surv_plot(dependent,
                      explanatory,
                      xlab='Time (months)',
                      pval=TRUE,
                      legend = 'none',
                      break.time.by = 12,
                      xlim = c(0,60),
                      legend.labs = c('a','b')
)

20.3 Sağkalım Tabloları

{r}
km_fit <- survfit(dependent ~ explanatory,
                  data = mydata)
km_fit
{r, eval=FALSE, include=FALSE}
library(survival)
km <- with(mydata, Surv(OverallTime, Outcome2))
# head(km,80)
# plot(km)
{r 1-3-5-yr}
summary(km_fit, times = c(12,36,60))

20.4 Pairwise comparison

{r}
survminer::pairwise_survdiff(formula = Surv(time, Outcome) ~ Group, 
                             data = mydata,
                             p.adjust.method = "BH")

20.5 Multivariate Analysis Survival

{r Multivariate Analysis, eval=FALSE, include=FALSE}
library(finalfit)
library(survival)
explanatoryMultivariate <- explanatoryKM
dependentMultivariate <- dependentKM
mydata %>%
  finalfit(dependentMultivariate, explanatoryMultivariate) -> tMultivariate
knitr::kable(tMultivariate, row.names=FALSE, align=c("l", "l", "r", "r", "r", "r"))

21 jamovi

21.1 jamovi ve R entegrasyonu

Rj Editor – Analyse your data with R in jamovi


21.2 {jmv} paket kodları

jamovi syntax mode


22 Güncellemeler olunca kodlar çalışacak mı?


22.1 Paket Kütüphaneleri

  • packrat / renv

https://environments.rstudio.com


22.2 Docker

  • docker

22.2.1 The Rocker Project

Docker Containers for the R Environment

docker run --rm -ti rocker/r-base

Or get started with an RStudio® instance:

docker run -e PASSWORD=yourpassword --rm -p 8787:8787 rocker/rstudio

and point your browser to localhost:8787 Log in with user/password rstudio/yourpassword


Managing containers


22.3 Yeni R sürümleri

  • RSwitch

https://rud.is/rswitch/

  • Using RSwitch

https://rud.is/rswitch/guide/

: scale 30%


23 Yedeklemeyi nasıl yapacağız

23.1 Projeyi düzgün organize edin

  • pdf
  • R
  • images
  • bib
{r load library}
source(file = here::here("R", "loadLibrary.R"))

23.2 Save Final Data

{r}
saved data after analysis to `mydata.xlsx`.

save.image(file = here::here("data", "mydata_work_space.RData"))

readr::write_rds(x = mydata, path = here::here("data", "mydata_afteranalysis.rds"))

saveRDS(object = mydata, file = here::here("data", "mydata.rds"))

writexl::write_xlsx(mydata, here::here("data", "mydata.xlsx"))

paste0(rownames(file.info(here::here("data", "mydata.xlsx"))), " : ", file.info(here::here("data", "mydata.xlsx"))$ctime)

23.3 GitHub

{r github push}
CommitMessage <- paste("updated on ", Sys.time(), sep = "")
wd <- getwd()
gitCommand <- paste("cd ", 
                    wd,
                    " \n git add . \n git commit --message '",
                    CommitMessage,
                    "' \n git push origin master \n",
                    sep = ""
                    )
system(command = gitCommand,
       intern = TRUE
)

23.4 GitHub Yedekleme

CommitMessage <- paste("updated on ", Sys.time(), sep = "")
wd <- getwd()
gitCommand <- paste("cd ", 
                    wd,
                    " \n git add . \n git commit --message '",
                    CommitMessage,
                    "' \n git push origin master \n",
                    sep = ""
                    )
system(command = gitCommand,
       intern = TRUE
)

24 Her dökümanın sonuna kullandığınız kütüphaneler için atıf yazdırabilirsiniz

{r}
citation()

24.1 Libraries Used

citation()

24.2 Bu oturuma spesifik kullanılan paketler

report::cite_packages(session = sessionInfo())

24.3 Tek tek paket atıfları

{r library citations}
citation("tidyverse")
citation("readxl")
citation("janitor")
citation("report")
citation("finalfit")
citation("ggstatplot")

24.4 Jamovi ve R için atıf örneği


25 Her dökümanın sonuna oturum detaylarınızı yazdırabilirsiniz

{r session info, echo=TRUE}
sessionInfo()

25.1 Session Info

sessionInfo()

26 Sonraki Konular

  • RStudio ile GitHub kullanımı

29 Geri Bildirim




  1. Bu bir derlemedir, mümkün mertebe alıntılara linklerle referans vermeye çalıştım.↩︎

LS0tCnRpdGxlOiBSLCBSU3R1ZGlvIHZlIFJNYXJrZG93biBpbGUgVGVrcmFybGFuYWJpbGlyIFJhcG9yXltCdSBiaXIgZGVybGVtZWRpciwgbcO8bWvDvG4gbWVydGViZSBhbMSxbnTEsWxhcmEgbGlua2xlcmxlIHJlZmVyYW5zIHZlcm1leWUgw6dhbMSxxZ90xLFtLl0KYXV0aG9yOiAiW1NlcmRhciBCYWxjxLEsIE1ELCBQYXRob2xvZ2lzdF0oaHR0cHM6Ly9zYmFsY2kuZ2l0aHViLmlvLykiCmluc3RpdHV0ZTogIltzZXJkYXJiYWxjaS5jb21dKGh0dHBzOi8vd3d3LnNlcmRhcmJhbGNpLmNvbSkiCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSlgIgpvdXRwdXQ6CiAgcmV2ZWFsanM6OnJldmVhbGpzX3ByZXNlbnRhdGlvbjoKICAgIGluY3JlbWVudGFsOiB0cnVlCiAgICB0aGVtZTogc2t5CiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICBjZW50ZXI6IGZhbHNlCiAgICBzbWFydDogdHJ1ZQogICAgdHJhbnNpdGlvbjogZmFkZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIGlnX3dpZHRoOiA3CiAgICBmaWdfaGVpZ2h0OiA2CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgcmV2ZWFsX29wdGlvbnM6CiAgICAgIHNsaWRlTnVtYmVyOiB0cnVlCiAgICAgIHByZXZpZXdMaW5rczogdHJ1ZQogIHJtZHNob3dlcjo6c2hvd2VyX3ByZXNlbnRhdGlvbjoKICB4YXJpbmdhbjo6bW9vbl9yZWFkZXI6CiAgICBsaWJfZGlyOiBsaWJzCiAgICBuYXR1cmU6CiAgICAgIGJlZm9yZUluaXQ6IFsibWFjcm9zLmpzIiwgImh0dHBzOi8vcGxhdGZvcm0udHdpdHRlci5jb20vd2lkZ2V0cy5qcyJdCiAgICAgIGhpZ2hsaWdodFN0eWxlOiBnaXRodWIKICAgICAgaGlnaGxpZ2h0TGluZXM6IHRydWUKICAgICAgY291bnRJbmNyZW1lbnRhbFNsaWRlczogZmFsc2UKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgaHRtbF9ub3RlYm9vazoKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGhpZ2hsaWdodDoga2F0ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBmbGF0bHkKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDogeWVzCiAgcHJldHR5ZG9jOjpodG1sX3ByZXR0eToKICAgIHRoZW1lOiBsZW9uaWRzCiAgICBoaWdobGlnaHQ6IGdpdGh1YgogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6ICc1JwogIGh0bWxfZG9jdW1lbnQ6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBrZWVwX21kOiB5ZXMKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDogeWVzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKCjwhLS0gT3BlbiBhbGwgbGlua3MgaW4gbmV3IHRhYi0tPiAgCjxiYXNlIHRhcmdldD0iX2JsYW5rIi8+ICAKCgo8IS0tIEdvIHRvIHd3dy5hZGR0aGlzLmNvbS9kYXNoYm9hcmQgdG8gY3VzdG9taXplIHlvdXIgdG9vbHMgLS0+IDxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0IiBzcmM9Ii8vczcuYWRkdGhpcy5jb20vanMvMzAwL2FkZHRoaXNfd2lkZ2V0LmpzI3B1YmlkPXJhLTViYzM2OTAwYTQwNTA5MGIiPiAgCjwvc2NyaXB0PgoKCgpgYGB7ciBnbG9iYWxfb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLnBhdGggPSAnRmlncy8nLCBlY2hvID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBlcnJvciA9IEZBTFNFLCBldmFsID0gVFJVRSwgdGlkeSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgY2FjaGUgPSBUUlVFKQpgYGAKCgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyB4YXJpbmdhbjo6aW5mX21yKCkKIyBzZXJ2cjo6ZGFlbW9uX3N0b3AoMSkKYGBgCgoKCiMgVGVrcmFybGFuYWJpbGlyIEFuYWxpeiB2ZSBSYXBvcgoKClshW10oaHR0cHM6Ly90aGUtdHVyaW5nLXdheS5uZXRsaWZ5LmNvbS9maWd1cmVzL3JlcHJvZHVjaWJpbGl0eS9SZXByb2R1Y2libGVNYXRyaXguanBnKV0oaHR0cHM6Ly90aGUtdHVyaW5nLXdheS5uZXRsaWZ5LmNvbS9yZXByb2R1Y2liaWxpdHkvMDMvZGVmaW5pdGlvbnMuaHRtbCkKCgoKCi0tLQoKCiMjIFJlcGxpY2F0aW9uIENyaXNpcwoKIVtdKGZpZ3VyZXMvcmVwbGljYXRpb25DcmlzaXMucG5nKQoKaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmVwbGljYXRpb25fY3Jpc2lzCgoKLS0tCgojIyBSZXBsaWNhdGlvbiBDcmlzaXMgRXhjZWwgVmVyc2lvbgoKWyFbXShmaWd1cmVzL2dlbmVOYW1lc0V4Y2VsLnBuZyldKGh0dHBzOi8vZ2Vub21lYmlvbG9neS5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2L3MxMzA1OS0wMTYtMTA0NC03KQoKCi0tLQoKIyBSU3R1ZGlvIGlsZSBwcm9qZSBvbHXFn3R1cgoKCgohW10oaW1hZ2VzL1JTdHVkaW8tTmV3UHJvamVjdC5naWYpCgoKCi0tLQoKIyBSIE5vdGVib29rICAKCiMjIFIgTm90ZWJvb2sgZMO2a8O8bWFuxLEgb2x1xZ90dXJtYSAKCgohW10oaW1hZ2VzL1JOb3RlYm9vazEuZ2lmKQoKLS0tCgojIyBSIE5vdGVib29rJ3RhbiBodG1sLCBwZGYgdmUgd29yZCBvbHXFn3R1cm1hICAKCgohW10oaW1hZ2VzL1JOb3RlYm9vazIuZ2lmKQoKCi0tLQoKIyMgUk5vdGVib29rIHZzIFJNYXJrZG93biAgCgo8aWZyYW1lIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2VtYmVkL3pOeloxUGZVRE5rIiBmcmFtZWJvcmRlcj0iMCIgYWxsb3c9ImFjY2VsZXJvbWV0ZXI7IGF1dG9wbGF5OyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+ICAKCmh0dHBzOi8veW91dHUuYmUvek56WjFQZlVETmsKCgotLS0KCiMgUiBNYXJrZG93bgoKIyMgSGVtIGtlbmRpIGtvZGxhcsSxIGhlbSBkZSBodG1sIGtvZGxhcsSxIHlhesSxbGFiaWxpcgoKaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20KCjxpZnJhbWUgc3JjPSJodHRwczovL3BsYXllci52aW1lby5jb20vdmlkZW8vMTc4NDg1NDE2P2NvbG9yPTQyOGJjYSZ0aXRsZT0wJmJ5bGluZT0wJnBvcnRyYWl0PTAiIHdpZHRoPSI2NDAiIGhlaWdodD0iNDAwIiBmcmFtZWJvcmRlcj0iMCIgYWxsb3c9ImF1dG9wbGF5OyBmdWxsc2NyZWVuIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+CjxwPjxhIGhyZWY9Imh0dHBzOi8vdmltZW8uY29tLzE3ODQ4NTQxNiI+V2hhdCBpcyBSIE1hcmtkb3duPzwvYT4gZnJvbSA8YSBocmVmPSJodHRwczovL3ZpbWVvLmNvbS9yc3R1ZGlvaW5jIj5SU3R1ZGlvLCBJbmMuPC9hPiBvbiA8YSBocmVmPSJodHRwczovL3ZpbWVvLmNvbSI+VmltZW88L2E+LjwvcD4KCi0tLQoKIyMgUiBNYXJrZG93bjogVGhlIERlZmluaXRpdmUgR3VpZGUKCmh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi8KCgotLS0KCiMjIFIgTWFya2Rvd24gc3ludGF4CgpodHRwczovL2dpc3QuZ2l0aHViLmNvbS9NaW5oYXNLYW1hbC83ZmRlYmI3YzQyNGQyMzE0OTE0MAoKCjxzY3JpcHQgc3JjPSJodHRwczovL2dpc3QuZ2l0aHViLmNvbS9NaW5oYXNLYW1hbC83ZmRlYmI3YzQyNGQyMzE0OTE0MC5qcyI+PC9zY3JpcHQ+CgoKCi0tLQoKIyMgUmVtZWR5IFBhY2thZ2UgIAoKWzxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vVGhpbmtSLW9wZW4vcmVtZWR5L21hc3Rlci9yZWZlcmVuY2UvZmlndXJlcy90aGlua3ItaGV4LXJlbWVkeS5wbmciIHdpZHRoPTI1MHB4Pl0oaHR0cHM6Ly9naXRodWIuY29tL1RoaW5rUi1vcGVuL3JlbWVkeSkKCgotLS0KCiMjIyBSZW1lZHkgIAoKWzxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vVGhpbmtSLW9wZW4vcmVtZWR5L21hc3Rlci9yZWZlcmVuY2UvZmlndXJlcy9yZW1lZHlfZXhhbXBsZS5naWYiIHdpZHRoPTUwMHB4Pl0oaHR0cHM6Ly9naXRodWIuY29tL1RoaW5rUi1vcGVuL3JlbWVkeSkKCgotLS0KCiMjIFIgTWFya2Rvd24gcGFrZXQgdmUgxZ9hYmxvbmxhcsSxICAKCmh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9kb2N1bWVudC10ZW1wbGF0ZXMuaHRtbAoKCiFbXShpbWFnZXMvUk1hcmtkb3duVGVtcGxhdGVzLmdpZikKCgotLS0KCiMjIFJlbmRlciBNYXJrZG93biB2aWEgY29kZQoKKmluc2lkZSBSKgoKYGBgCm1hcmtkb3duOjptYXJrZG93blRvSFRNTCgnbWFya2Rvd25fZXhhbXBsZS5tZCcsIAonbWFya2Rvd25fZXhhbXBsZS5odG1sJykKYGBgCgoqY29tbWFuZCBsaW5lKgoKYGBgClIgLWUgIm1hcmtkb3duOjptYXJrZG93blRvSFRNTCgnbWFya2Rvd25fZXhhbXBsZS5tZCcsCidtYXJrZG93bl9leGFtcGxlLmh0bWwnKSIKYGBgCgotLS0KCgojIyBwYW5kb2MgUnN0dWRpbyBpbnRlZ3JhdGlvbgoKKmNvbW1hbmQgbGluZSoKCmBgYApleHBvcnQgUEFUSD0kUEFUSDovQXBwbGljYXRpb25zL1JTdHVkaW8uYXBwL0NvbnRlbnRzL01hY09TL3BhbmRvYwpgYGAKCgpgYGAKUiAtZSAicm1hcmtkb3duOjpyZW5kZXIoJ21hcmtkb3duX2V4YW1wbGUubWQnKSIKYGBgCgoKLS0tCgojIFJNYXJrZG93biBgY2h1bmtgIGnDp2luZGUgYFJgIGtvZGxhcsSxbsSxIMOnYWzEscWfdMSxcm1hCgoKYGBgCntyLCByZXN1bHRzPSdhc2lzJ30KIGlyaXMgJT4lCiAgdGliYmxlOjphc190aWJibGUoKSAlPiUKICBkZXRhaWxzOjpkZXRhaWxzKHN1bW1hcnkgPSAndGliYmxlJykKYGBgCgotLS0KCiMgTWV0aW4gYXJhc8SxbmRhIGBSYCBrb2RsYXLEsW7EsSDDp2FsxLHFn3TEsXJtYQoKCiFbXShpbWFnZXMvaW5saW5lUkNvZGUucG5nKQoKCi0tLQoKIyBDaHVuayBPcHRpb25zCgojIyBHbG9iYWwgT3B0aW9ucwoKYGBgCntyIGdsb2JhbF9vcHRpb25zLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gOCwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5wYXRoID0gJ0ZpZ3MvJywKICAgICAgICAgICAgICAgICAgICAgIGVjaG8gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGVycm9yID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBldmFsID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIHRpZHkgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BKQpgYGAKCi0tLQoKIyMgT3RoZXIgQ29kZSBMYW5ndWFnZXMKCgpbIVtdKGh0dHBzOi8vZDMzd3VicmZraTBsNjguY2xvdWRmcm9udC5uZXQvMTYyMzQ3ZWY1YWZlMjE5ZGEyMmZiN2Q3ZDlhNTk4OWYyYzNlNWE4NS81OTMxNi9sZXNzb24taW1hZ2VzL2xhbmd1YWdlcy0xLWRlbW9zLnBuZyldKGh0dHBzOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tL2xlc3Nvbi01Lmh0bWwpCgoKLS0tCgoKIyBSIE1hcmtkb3duIGtvZCDDtnJuZcSfaSAgCgoKYGBgCntyfQpkYXRhKCJjYW5jZXIiKQpjYW5jZXIKZm9yZWlnbjo6d3JpdGUuZm9yZWlnbihkZiA9IGNhbmNlciwKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YWZpbGUgPSAiZGF0YS9jYW5jZXIuc2F2IiwKICAgICAgICAgICAgICAgICAgICAgICAgY29kZWZpbGUgPSAiZGF0YS9jYW5jZXIuc3BvIiwKICAgICAgICAgICAgICAgICAgICAgICAgcGFja2FnZSA9ICJTUFNTIgogICAgICAgICAgICAgICAgICAgICAgICApCmBgYAoKCi0tLQoKIyBSIE1hcmtkb3duIFBha2V0IMOHYcSfxLFybWEg8J+TpiAgICAKCgpgYGAKe3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KCJ0aWR5dmVyc2UiKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoInN1cnZpdmFsIikpCmBgYAoKLS0tCgojIyBTxLFrIGt1bGxhbmTEscSfxLFtIHBha2V0bGVyIPCfk6YgIAoKe3RpZHl2ZXJzZX0Ke3RpZHlsb2d9Cgp7bHVicmlkYXRlfQp7amFuaXRvcn0KCntyZWFkeGx9Cntmb3JlaWdufQoKe3N1bW1hcnl0b29sc30Ke2dnc3RhdHNwbG90fQp7dGFuZ3JhbX0Ke2ZpbmFsZml0fQp7cHN5Y2hvfQp7am12fQoKe3N1cnZpdmFsfQp7c3Vydm1pbmVyfQoKe3JlcG9ydH0Ke2thYmxlRXh0cmF9CgotLS0KCiMgUiBNYXJrZG93biBWZXJpIFnDvGtsZW1lIFNQU1MgIAoKIVtdKGltYWdlcy9pbXBvcnRTUFNTLmdpZikKCgotLS0KCiMgUiBNYXJrZG93biBWZXJpIFnDvGtsZW1lIEV4Y2VsICAKCgoKIVtdKGltYWdlcy9pbXBvcnRFeGNlbC5naWYpCgoKLS0tCgojIFZlcmkgR8O2csO8bnTDvGxlbWUKCgpgYGAKe3J9ClZpZXcobXlkYXRhKQpnbGltcHNlKG15ZGF0YSkKYGBgCgoKCgotLS0KCiMgVmVyaSBEw7x6ZW5sZW1lCgpgYGAKe3J9Cm15ZGF0YSA8LSBqYW5pdG9yOjpjbGVhbl9uYW1lcyhteWRhdGEpCmBgYAoKYGBgCntyfQpteWRhdGEkc29udGFyaWggPC0gamFuaXRvcjo6ZXhjZWxfbnVtZXJpY190b19kYXRlKAogIGFzLm51bWVyaWMobXlkYXRhJG9sdW1fdGFyaWhpKQogICkKYGBgCgoKLS0tCgojIFJlY29kZQoKCmBgYAp7cn0KbXlkYXRhJE91dGNvbWUgPC0gIkRlYWQiCm15ZGF0YSRPdXRjb21lW215ZGF0YSRvbHVtX3RhcmloaSA9PSAieW9rIl0gPC0gIkFsaXZlIgpgYGAKCgpgYGAKe3J9CiMjIFJlY29kaW5nIG15ZGF0YSRjaW5zaXlldCBpbnRvIG15ZGF0YSRDaW5zaXlldApteWRhdGEkQ2luc2l5ZXQgPC0gcmVjb2RlKG15ZGF0YSRjaW5zaXlldCwKICAgICAgICAgICAgICAgIksiID0gIkthZGluIiwKICAgICAgICAgICAgICAgIkUiID0gIkVya2VrIikKbXlkYXRhJENpbnNpeWV0IDwtIGZhY3RvcihteWRhdGEkQ2luc2l5ZXQpCmBgYAoKCi0tLQoKIyBSZWNvZGUgcmVndWxhciBleHByZXNzaW9uCgoKYGBgCntyIHJlY29kZSBUTk0gc3RhZ2V9CiNwVDJOME14IC0+IDIKbXlkYXRhJFRzdGFnZSA8LSBzdHJpbmdyOjpzdHJfbWF0Y2goCiAgbXlkYXRhJHBhdG9sb2ppa19ldnJlLCAKICBwYXN0ZSgnKC4rKScsICJOIiwgc2VwPScnKSlbLDJdCikKYGBgCgoKLS0tCgojIFJlY29kZSByZWd1bGFyIGV4cHJlc3Npb24gY2FzZV93aGVuCgpgYGAKe3IgcmVjb2RlIFROTTJ9Cm15ZGF0YSA8LSBteWRhdGEgJT4lIAogICAgbXV0YXRlKAogICAgICAgIFRfc3RhZ2UgPSBjYXNlX3doZW4oCiAgICAgICAgICAgIGdyZXBsKHBhdHRlcm4gPSAiVDEiLCB4ID0gLiRUc3RhZ2UpID09IFRSVUUgfiAiVDEiLAogICAgICAgICAgICBncmVwbChwYXR0ZXJuID0gIlQyIiwgeCA9IC4kVHN0YWdlKSA9PSBUUlVFIH4gIlQyIiwKICAgICAgICAgICAgZ3JlcGwocGF0dGVybiA9ICJUMyIsIHggPSAuJFRzdGFnZSkgPT0gVFJVRSB+ICJUMyIsCiAgICAgICAgICAgIGdyZXBsKHBhdHRlcm4gPSAiVDQiLCB4ID0gLiRUc3RhZ2UpID09IFRSVUUgfiAiVDQiLAogICAgICAgICAgICBUUlVFIH4gIlR4IgogICAgICAgICkKICAgICkKYGBgCgotLS0KCiMgUmVjb2RlIHJlZ3VsYXIgZXhwcmVzc2lvbiBjYXNlX3doZW4KCmBgYAp7cn0KbXlkYXRhIDwtIG15ZGF0YSAlPiUgCiAgICBtdXRhdGUoClR1bW9yUERMMWdyMSA9IGNhc2Vfd2hlbigKICAgICAgICB0X3BkbDEgPCAxIH4gImt1Y3VrMSIsCiAgICAgICAgdF9wZGwxID49IDEgfiAiYnV5dWtlc2l0MSIKICAgICkKICAgICkKYGBgCgotLS0KCiMgUiBNYXJrZG93biBUYW7EsW1sYXnEsWPEsSDEsHN0YXRpc3Rpa2xlciAgCgoKYGBgCntyfQpsaWJyYXJ5KHN1bW1hcnl0b29scykKdmlldyhkZlN1bW1hcnkoY29sb25fcykpCmBgYAoKCi0tLQoKCkEgYmVnaW5uZXIga2l0IGZvciAjcnN0YXRzClRoZSBMYW5kc2NhcGUgb2YgUiBQYWNrYWdlcyBmb3IgQXV0b21hdGVkIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMKaHR0cHM6Ly9qb3VybmFsLnItcHJvamVjdC5vcmcvYXJjaGl2ZS8yMDE5L1JKLTIwMTktMDMzLwoKCgpAYXJ0aWNsZXtSSi0yMDE5LTAzMywKICBhdXRob3IgPSB7TWF0ZXVzeiBTdGFuaWFrIGFuZCBQcnplbXlzxYJhdyBCaWVjZWt9LAogIHRpdGxlID0ge3tUaGUgTGFuZHNjYXBlIG9mIFIgUGFja2FnZXMgZm9yIEF1dG9tYXRlZCBFeHBsb3JhdG9yeSBEYXRhCiAgICAgICAgICBBbmFseXNpc319LAogIHllYXIgPSB7MjAxOX0sCiAgam91cm5hbCA9IHt7VGhlIFIgSm91cm5hbH19LAogIGRvaSA9IHsxMC4zMjYxNC9SSi0yMDE5LTAzM30sCiAgdXJsID0ge2h0dHBzOi8vam91cm5hbC5yLXByb2plY3Qub3JnL2FyY2hpdmUvMjAxOS9SSi0yMDE5LTAzMy9pbmRleC5odG1sfQp9CgoKCi0tLQoKCiMjIFRhYmxlIE9uZSAgCgoKYGBgCntyLCByZXN1bHRzPSdhc2lzJ30KIyBjYXQobmFtZXMobXlkYXRhKSwgc2VwID0gIiArIFxuIikKbGlicmFyeShhcnNlbmFsKQp0YWIxIDwtIHRhYmxlYnkofiBDaW5zaXlldCArIApZYXMgKyAKVHVtb3JZZXJsZXNpbWkKICAgICAgICAgICAgICAgICwKICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEpCnN1bW1hcnkodGFiMSkKYGBgCgotLS0KCiMjIFRoZSBHcmFtbWFyIG9mIFRhYmxlcwoKClt0YW5ncmFtOiBUaGUgR3JhbW1hciBvZiBUYWJsZXNdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy90YW5ncmFtLykKCltBIGdyYW1tYXIgb2YgdGFibGVzXShodHRwczovL2dpdGh1Yi5jb20vbGVlcGVyL3R0dGFibGUpCgpbR3JhbW1hciBvZiBUYWJsZXM/XShodHRwczovL2dpc3QuZ2l0aHViLmNvbS9sZWVwZXIvZjljZmJlNmJkMTg1NzYzNzYyZTEyNmE0ZDhkN2MyODYpCgpbRWFzaWx5IGdlbmVyYXRlIGluZm9ybWF0aW9uLXJpY2gsIHB1YmxpY2F0aW9uLXF1YWxpdHkgdGFibGVzIGZyb20gUl0oaHR0cHM6Ly9ndC5yc3R1ZGlvLmNvbSkKCgotLS0KCiMjIEthdGVnb3JpayBWZXJpbGVyCgpgYGAKe3J9Cm15ZGF0YSAlPiUgCiAgamFuaXRvcjo6dGFieWwoQ2F0ZWdvcmljYWwpICU+JQogIGFkb3JuX3BjdF9mb3JtYXR0aW5nKHJvdW5kaW5nID0gJ2hhbGYgdXAnLAogICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDEpICU+JQogIGtuaXRyOjprYWJsZSgpCmBgYAoKYGBgCntyIGNyb3NzdGFibGV9Cm15ZGF0YSAlPiUKICAgIHN1bW1hcnlfZmFjdG9ybGlzdChkZXBlbmRlbnQgPSBkZXBlbmRlbnQsIAogICAgICAgICAgICAgICAgICAgICAgIGV4cGxhbmF0b3J5ID0gZXhwbGFuYXRvcnksCiAgICAgICAgICAgICAgICAgICAgICAgdG90YWxfY29sID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICBwID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICBhZGRfZGVwZW5kZW50X2xhYmVsID0gVFJVRSkgLT4gdGFibGUKa25pdHI6OmthYmxlKHRhYmxlLCByb3cubmFtZXMgPSBGQUxTRSwgYWxpZ24gPSBjKCdsJywgJ2wnLCAncicsICdyJywgJ3InKSkKYGBgCgotLS0KCiMjIEthdGVnb3JpayBWZXJpbGVyIGnDp2luIEdyYWZpa2xlciAgCgpgYGAKe3IgZ2dzdGF0cGxvdCwgbGF5b3V0PSdsLXBhZ2UnfQpteWRhdGEgJT4lIAogICAgZ2dzdGF0c3Bsb3Q6OmdnYmFyc3RhdHMoZGF0YSA9IC4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWluID0gQ2F0ZWdvcmljYWxfdmFyaWFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25kaXRpb24gPSAgZGVwZW5kZW50X3ZhcmlhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApCmBgYAoKLS0tCgoKIyMgQ29udGluaW91cyBWYXJpYWJsZXMKCmBgYAp7cn0KbXlkYXRhICU+JSAKam12OjpkZXNjcmlwdGl2ZXMoCiAgICBkYXRhID0gLiwKICAgIHZhcnMgPSBjKHlhcyksCiAgICBoaXN0ID0gVFJVRSwKICAgIGRlbnMgPSBUUlVFLAogICAgYm94ID0gVFJVRSwKICAgIHZpb2xpbiA9IFRSVUUsCiAgICBkb3QgPSBUUlVFLAogICAgbW9kZSA9IFRSVUUsCiAgICBzZCA9IFRSVUUsCiAgICB2YXJpYW5jZSA9IFRSVUUsCiAgICBza2V3ID0gVFJVRSwKICAgIGt1cnQgPSBUUlVFLAogICAgcXVhcnQgPSBUUlVFKQpgYGAKCi0tLQoKIyBSIE1hcmtkb3duIMO2cm5lxJ9pIMOHYXByYXogVGFibG9sYXIgIAoKYGBgCntyIGNyb3NzdGFibGV9CmxpYnJhcnkoZmluYWxmaXQpCm15ZGF0YSAlPiUKICAgIHN1bW1hcnlfZmFjdG9ybGlzdChkZXBlbmRlbnQgPSBkZXBlbmRlbnQsIAogICAgICAgICAgICAgICAgICAgICAgIGV4cGxhbmF0b3J5ID0gZXhwbGFuYXRvcnksCiAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICB0b3RhbF9jb2wgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIHAgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIGFkZF9kZXBlbmRlbnRfbGFiZWwgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIG5hX2luY2x1ZGU9RkFMU0UKICAgICAgICAgICAgICAgICAgICAgICAjIGNhdFRlc3QgPSBjYXRUZXN0ZmlzaGVyCiAgICAgICAgICAgICAgICAgICAgICAgKSAtPiB0YWJsZQprbml0cjo6a2FibGUodGFibGUsCiAgICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgIGFsaWduID0gYygnbCcsICdsJywgJ3InLCAncicsICdyJykpCmBgYAoKLS0tCgojIFIgTWFya2Rvd24gw7ZybmXEn2kgU2HEn2thbMSxbSAgCgotIERyYXdpbmcgU3Vydml2YWwgQ3VydmVzIFVzaW5nIGdncGxvdDIgIApodHRwczovL3Jwa2dzLmRhdGFub3ZpYS5jb20vc3Vydm1pbmVyL3JlZmVyZW5jZS9nZ3N1cnZwbG90Lmh0bWwKCiMjIFNhxJ9rYWzEsW0gacOnaW4gdmVyaXlpIGTDvHplbmxlbWUKCmBgYAp7ciBkZWZpbmUgc3Vydml2YWwgdGltZX0KbXlkYXRhJGludCA8LSBsdWJyaWRhdGU6OmludGVydmFsKAogIGx1YnJpZGF0ZTo6eW1kKG15ZGF0YSRDZXJyYWhpVGFyaWgpLAogIGx1YnJpZGF0ZTo6eW1kKG15ZGF0YSRTb25UYXJpaCkKICApCm15ZGF0YSRPdmVyYWxsVGltZSA8LSBsdWJyaWRhdGU6OnRpbWVfbGVuZ3RoKG15ZGF0YSRpbnQsICJtb250aCIpCm15ZGF0YSRPdmVyYWxsVGltZSA8LSByb3VuZChteWRhdGEkT3ZlcmFsbFRpbWUsIGRpZ2l0cyA9IDEpCmBgYAoKYGBgCntyfQojIyBSZWNvZGluZyBteWRhdGEkT3V0Y29tZSBpbnRvIG15ZGF0YSRPdXRjb21lMgpteWRhdGEkT3V0Y29tZTIgPC0gcmVjb2RlKG15ZGF0YSRPdXRjb21lLAogICAgICAgICAgICAgICAiQWxpdmUiID0gIjAiLAogICAgICAgICAgICAgICAiRGVhZCIgPSAiMSIpCm15ZGF0YSRPdXRjb21lMiA8LSBhcy5udW1lcmljKG15ZGF0YSRPdXRjb21lMikKYGBgCgotLS0KCiMjIEthcGxhbi1NZWllcgoKYGBgCntyIEthcGxhbi1NZWllcn0KbXlkYXRhICU+JQogIGZpbmFsZml0OjpzdXJ2X3Bsb3QoZGVwZW5kZW50LAogICAgICAgICAgICAgICAgICAgICAgZXhwbGFuYXRvcnksCiAgICAgICAgICAgICAgICAgICAgICB4bGFiPSdUaW1lIChtb250aHMpJywKICAgICAgICAgICAgICAgICAgICAgIHB2YWw9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZCA9ICdub25lJywKICAgICAgICAgICAgICAgICAgICAgIGJyZWFrLnRpbWUuYnkgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgIHhsaW0gPSBjKDAsNjApLAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmxhYnMgPSBjKCdhJywnYicpCikKYGBgCgotLS0KCiMjIFNhxJ9rYWzEsW0gVGFibG9sYXLEsQoKYGBgCntyfQprbV9maXQgPC0gc3VydmZpdChkZXBlbmRlbnQgfiBleHBsYW5hdG9yeSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG15ZGF0YSkKa21fZml0CmBgYAoKYGBgCntyLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KHN1cnZpdmFsKQprbSA8LSB3aXRoKG15ZGF0YSwgU3VydihPdmVyYWxsVGltZSwgT3V0Y29tZTIpKQojIGhlYWQoa20sODApCiMgcGxvdChrbSkKYGBgCgpgYGAKe3IgMS0zLTUteXJ9CnN1bW1hcnkoa21fZml0LCB0aW1lcyA9IGMoMTIsMzYsNjApKQpgYGAKCi0tLQoKIyMgUGFpcndpc2UgY29tcGFyaXNvbgoKYGBgCntyfQpzdXJ2bWluZXI6OnBhaXJ3aXNlX3N1cnZkaWZmKGZvcm11bGEgPSBTdXJ2KHRpbWUsIE91dGNvbWUpIH4gR3JvdXAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gIkJIIikKYGBgCgotLS0KCiMjIE11bHRpdmFyaWF0ZSBBbmFseXNpcyBTdXJ2aXZhbAoKYGBgCntyIE11bHRpdmFyaWF0ZSBBbmFseXNpcywgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShmaW5hbGZpdCkKbGlicmFyeShzdXJ2aXZhbCkKZXhwbGFuYXRvcnlNdWx0aXZhcmlhdGUgPC0gZXhwbGFuYXRvcnlLTQpkZXBlbmRlbnRNdWx0aXZhcmlhdGUgPC0gZGVwZW5kZW50S00KbXlkYXRhICU+JQogIGZpbmFsZml0KGRlcGVuZGVudE11bHRpdmFyaWF0ZSwgZXhwbGFuYXRvcnlNdWx0aXZhcmlhdGUpIC0+IHRNdWx0aXZhcmlhdGUKa25pdHI6OmthYmxlKHRNdWx0aXZhcmlhdGUsIHJvdy5uYW1lcz1GQUxTRSwgYWxpZ249YygibCIsICJsIiwgInIiLCAiciIsICJyIiwgInIiKSkKYGBgCgotLS0KCiMgamFtb3ZpCgojIyBqYW1vdmkgdmUgUiBlbnRlZ3Jhc3lvbnUKCltSaiBFZGl0b3Ig4oCTIEFuYWx5c2UgeW91ciBkYXRhIHdpdGggUiBpbiBqYW1vdmldKGh0dHBzOi8vYmxvZy5qYW1vdmkub3JnLzIwMTgvMDcvMzAvcmouaHRtbCkKCiFbXShpbWFnZXMvamFtb3ZpUmpFZGl0b3IuZ2lmKQoKLS0tCgojIyB7am12fSBwYWtldCBrb2RsYXLEsQoKW2phbW92aSBzeW50YXggbW9kZV0oaHR0cHM6Ly93d3cuamFtb3ZpLm9yZy91c2VyLW1hbnVhbC5odG1sI3N5bnRheC1tb2RlKQoKCiFbXShpbWFnZXMvamFtb3ZpU3ludGF4TW9kZS5naWYpCgoKCi0tLQoKIyBHw7xuY2VsbGVtZWxlciBvbHVuY2Ega29kbGFyIMOnYWzEscWfYWNhayBtxLE/CgoKLS0tCgojIyBQYWtldCBLw7x0w7xwaGFuZWxlcmkKCi0gcGFja3JhdCAvIHJlbnYKCmh0dHBzOi8vZW52aXJvbm1lbnRzLnJzdHVkaW8uY29tCgotLS0KCiMjIERvY2tlcgoKLSBkb2NrZXIKCi0tLQoKIyMjIFRoZSBSb2NrZXIgUHJvamVjdAoKRG9ja2VyIENvbnRhaW5lcnMgZm9yIHRoZSBSIEVudmlyb25tZW50CgpgYGAKZG9ja2VyIHJ1biAtLXJtIC10aSByb2NrZXIvci1iYXNlCmBgYAoKT3IgZ2V0IHN0YXJ0ZWQgd2l0aCBhbiBSU3R1ZGlvwq4gaW5zdGFuY2U6CgpgYGAKZG9ja2VyIHJ1biAtZSBQQVNTV09SRD15b3VycGFzc3dvcmQgLS1ybSAtcCA4Nzg3Ojg3ODcgcm9ja2VyL3JzdHVkaW8KYGBgCgphbmQgcG9pbnQgeW91ciBicm93c2VyIHRvIFtsb2NhbGhvc3Q6ODc4N10obG9jYWxob3N0Ojg3ODcpCkxvZyBpbiB3aXRoIHVzZXIvcGFzc3dvcmQgcnN0dWRpby95b3VycGFzc3dvcmQgCgotLS0KClshW10oaW1hZ2VzL1RoZVJvY2tlclByb2plY3QucG5nKV0oaHR0cHM6Ly93d3cucm9ja2VyLXByb2plY3Qub3JnKQoKW01hbmFnaW5nIGNvbnRhaW5lcnNdKGh0dHBzOi8vd3d3LnJvY2tlci1wcm9qZWN0Lm9yZy91c2UvbWFuYWdpbmdfY29udGFpbmVycy8pCgoKLS0tCgojIyBZZW5pIFIgc8O8csO8bWxlcmkgCgotIFJTd2l0Y2gKCmh0dHBzOi8vcnVkLmlzL3Jzd2l0Y2gvCgotIFVzaW5nIFJTd2l0Y2gKCmh0dHBzOi8vcnVkLmlzL3Jzd2l0Y2gvZ3VpZGUvCgoKIVs6IHNjYWxlIDMwJV0oaHR0cHM6Ly9ydWQuaXMvcnN3aXRjaC9ndWlkZS9tZW51LWluZm8ucG5nKQoKCi0tLQoKIyBZZWRla2xlbWV5aSBuYXPEsWwgeWFwYWNhxJ/EsXoKCiMjIFByb2pleWkgZMO8emfDvG4gb3JnYW5pemUgZWRpbgoKLSBwZGYKLSBSCi0gaW1hZ2VzCi0gYmliCgpgYGAKe3IgbG9hZCBsaWJyYXJ5fQpzb3VyY2UoZmlsZSA9IGhlcmU6OmhlcmUoIlIiLCAibG9hZExpYnJhcnkuUiIpKQpgYGAKCi0tLQoKIyMgU2F2ZSBGaW5hbCBEYXRhCgpgYGAKe3J9CnNhdmVkIGRhdGEgYWZ0ZXIgYW5hbHlzaXMgdG8gYG15ZGF0YS54bHN4YC4KCnNhdmUuaW1hZ2UoZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCAibXlkYXRhX3dvcmtfc3BhY2UuUkRhdGEiKSkKCnJlYWRyOjp3cml0ZV9yZHMoeCA9IG15ZGF0YSwgcGF0aCA9IGhlcmU6OmhlcmUoImRhdGEiLCAibXlkYXRhX2FmdGVyYW5hbHlzaXMucmRzIikpCgpzYXZlUkRTKG9iamVjdCA9IG15ZGF0YSwgZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCAibXlkYXRhLnJkcyIpKQoKd3JpdGV4bDo6d3JpdGVfeGxzeChteWRhdGEsIGhlcmU6OmhlcmUoImRhdGEiLCAibXlkYXRhLnhsc3giKSkKCnBhc3RlMChyb3duYW1lcyhmaWxlLmluZm8oaGVyZTo6aGVyZSgiZGF0YSIsICJteWRhdGEueGxzeCIpKSksICIgOiAiLCBmaWxlLmluZm8oaGVyZTo6aGVyZSgiZGF0YSIsICJteWRhdGEueGxzeCIpKSRjdGltZSkKCmBgYAoKLS0tCgojIyBHaXRIdWIgIAoKYGBgCntyIGdpdGh1YiBwdXNofQpDb21taXRNZXNzYWdlIDwtIHBhc3RlKCJ1cGRhdGVkIG9uICIsIFN5cy50aW1lKCksIHNlcCA9ICIiKQp3ZCA8LSBnZXR3ZCgpCmdpdENvbW1hbmQgPC0gcGFzdGUoImNkICIsIAogICAgICAgICAgICAgICAgICAgIHdkLAogICAgICAgICAgICAgICAgICAgICIgXG4gZ2l0IGFkZCAuIFxuIGdpdCBjb21taXQgLS1tZXNzYWdlICciLAogICAgICAgICAgICAgICAgICAgIENvbW1pdE1lc3NhZ2UsCiAgICAgICAgICAgICAgICAgICAgIicgXG4gZ2l0IHB1c2ggb3JpZ2luIG1hc3RlciBcbiIsCiAgICAgICAgICAgICAgICAgICAgc2VwID0gIiIKICAgICAgICAgICAgICAgICAgICApCnN5c3RlbShjb21tYW5kID0gZ2l0Q29tbWFuZCwKICAgICAgIGludGVybiA9IFRSVUUKKQpgYGAKCi0tLQoKIyMgR2l0SHViIFllZGVrbGVtZQoKYGBge3IgZ2l0aHViIHB1c2gsIGVjaG89VFJVRX0KQ29tbWl0TWVzc2FnZSA8LSBwYXN0ZSgidXBkYXRlZCBvbiAiLCBTeXMudGltZSgpLCBzZXAgPSAiIikKd2QgPC0gZ2V0d2QoKQpnaXRDb21tYW5kIDwtIHBhc3RlKCJjZCAiLCAKICAgICAgICAgICAgICAgICAgICB3ZCwKICAgICAgICAgICAgICAgICAgICAiIFxuIGdpdCBhZGQgLiBcbiBnaXQgY29tbWl0IC0tbWVzc2FnZSAnIiwKICAgICAgICAgICAgICAgICAgICBDb21taXRNZXNzYWdlLAogICAgICAgICAgICAgICAgICAgICInIFxuIGdpdCBwdXNoIG9yaWdpbiBtYXN0ZXIgXG4iLAogICAgICAgICAgICAgICAgICAgIHNlcCA9ICIiCiAgICAgICAgICAgICAgICAgICAgKQpzeXN0ZW0oY29tbWFuZCA9IGdpdENvbW1hbmQsCiAgICAgICBpbnRlcm4gPSBUUlVFCikKYGBgCgotLS0KCiMgSGVyIGTDtmvDvG1hbsSxbiBzb251bmEga3VsbGFuZMSxxJ/EsW7EsXoga8O8dMO8cGhhbmVsZXIgacOnaW4gYXTEsWYgeWF6ZMSxcmFiaWxpcnNpbml6CgpgYGAKe3J9CmNpdGF0aW9uKCkKYGBgCgotLS0KCiMjIExpYnJhcmllcyBVc2VkICAKCmBgYHtyIGxpYnJhcnkgY2l0YXRpb24sIGVjaG89VFJVRX0KY2l0YXRpb24oKQpgYGAKCi0tLQoKIyMgQnUgb3R1cnVtYSBzcGVzaWZpayBrdWxsYW7EsWxhbiBwYWtldGxlciAgCgpgYGB7ciBsaWJyYXJ5IGNpdGF0aW9uIGFzIHJlcG9ydCwgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KcmVwb3J0OjpjaXRlX3BhY2thZ2VzKHNlc3Npb24gPSBzZXNzaW9uSW5mbygpKQpgYGAKCgotLS0KCiMjIFRlayB0ZWsgcGFrZXQgYXTEsWZsYXLEsQoKCmBgYAp7ciBsaWJyYXJ5IGNpdGF0aW9uc30KY2l0YXRpb24oInRpZHl2ZXJzZSIpCmNpdGF0aW9uKCJyZWFkeGwiKQpjaXRhdGlvbigiamFuaXRvciIpCmNpdGF0aW9uKCJyZXBvcnQiKQpjaXRhdGlvbigiZmluYWxmaXQiKQpjaXRhdGlvbigiZ2dzdGF0cGxvdCIpCmBgYAoKCi0tLQoKIyMgSmFtb3ZpIHZlIFIgacOnaW4gYXTEsWYgw7ZybmXEn2kKCi0gVGhlIGphbW92aSBwcm9qZWN0ICgyMDE5KS4gamFtb3ZpLiAoVmVyc2lvbiAwLjkpIFtDb21wdXRlciBTb2Z0d2FyZV0uIFJldHJpZXZlZCBmcm9tIGh0dHBzOi8vd3d3LmphbW92aS5vcmcuCgotIFIgQ29yZSBUZWFtICgyMDE4KS4gUjogQSBMYW5ndWFnZSBhbmQgZW52aW9ubWVudCBmb3Igc3RhdGlzdGljYWwgY29tcHV0aW5nLiBbQ29tcHV0ZXIgc29mdHdhcmVdLiBSZXRyaWV2ZWQgZnJvbSBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy8uCgotIEZveCwgSi4sICYgV2Vpc2JlcmcsIFMuICgyMDE4KS4gY2FyOiBDb21wYW5pb24gdG8gQXBwbGllZCBSZWdyZXNzaW9uLiBbUiBwYWNrYWdlXS4gUmV0cmlldmVkIGZyb20gaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvcGFja2FnZT1jYXIuCgoKCi0tLQoKIyBIZXIgZMO2a8O8bWFuxLFuIHNvbnVuYSBvdHVydW0gZGV0YXlsYXLEsW7EsXrEsSB5YXpkxLFyYWJpbGlyc2luaXogIAoKYGBgCntyIHNlc3Npb24gaW5mbywgZWNobz1UUlVFfQpzZXNzaW9uSW5mbygpCmBgYAoKLS0tCgojIyBTZXNzaW9uIEluZm8KCmBgYHtyIHNlc3Npb24gaW5mbywgZWNobz1UUlVFfQpzZXNzaW9uSW5mbygpCmBgYAoKLS0tCgojIFNvbnJha2kgS29udWxhcgoKLSBSU3R1ZGlvIGlsZSBHaXRIdWIga3VsbGFuxLFtxLEKLSAuLi4KCi0tLQoKIyDDlm5lcmlsZW4gS2F5bmFrbGFyCgotIFtSZXByb2R1Y2libGUgVGVtcGxhdGVzIGZvciBBbmFseXNpcyBhbmQgRGlzc2VtaW5hdGlvbl0oaHR0cHM6Ly93d3cuY291cnNlcmEub3JnL2xlYXJuL3JlcHJvZHVjaWJsZS10ZW1wbGF0ZXMtYW5hbHlzaXMvaG9tZS9pbmZvKQoKLSBbSGFwcHkgR2l0IGFuZCBHaXRIdWIgZm9yIHRoZSB1c2VSXShodHRwczovL2hhcHB5Z2l0d2l0aHIuY29tLykKCgoKCgotLS0KCiMgU3VudW0gTGlua2xlcmkKCmh0dHBzOi8vc2JhbGNpLmdpdGh1Yi5pby9NeVJDb2Rlc0ZvckRhdGFBbmFseXNpcy9SLU1hcmtkb3duLm5iLmh0bWwKaHR0cHM6Ly9zYmFsY2kuZ2l0aHViLmlvL015UkNvZGVzRm9yRGF0YUFuYWx5c2lzL1ItTWFya2Rvd24uaHRtbAoKaHR0cHM6Ly9mb3Jtcy5nbGUvVXFHSkJpQWpCOHVMUFJvbjgKCi0tLQoKIyBHZXJpIEJpbGRpcmltCgotIEdlcmkgYmlsZGlyaW0gacOnaW4gdMSxa2xhecSxbsSxejogX1tHZXJpIGJpbGRpcmltIGZvcm11XShodHRwczovL2dvby5nbC9mb3Jtcy9ZakdaNURIZ3RQbFIxUm5CMylfCgoKLS0tCgo8c2NyaXB0IGlkPSJkc3EtY291bnQtc2NyIiBzcmM9Ii8vaHR0cHMtc2JhbGNpLWdpdGh1Yi1pby5kaXNxdXMuY29tL2NvdW50LmpzIiBhc3luYz48L3NjcmlwdD4KCjxkaXYgaWQ9ImRpc3F1c190aHJlYWQiPjwvZGl2Pgo8c2NyaXB0PgoKLyoqCiogIFJFQ09NTUVOREVEIENPTkZJR1VSQVRJT04gVkFSSUFCTEVTOiBFRElUIEFORCBVTkNPTU1FTlQgVEhFIFNFQ1RJT04gQkVMT1cgVE8gSU5TRVJUIERZTkFNSUMgVkFMVUVTIEZST00gWU9VUiBQTEFURk9STSBPUiBDTVMuCiogIExFQVJOIFdIWSBERUZJTklORyBUSEVTRSBWQVJJQUJMRVMgSVMgSU1QT1JUQU5UOiBodHRwczovL2Rpc3F1cy5jb20vYWRtaW4vdW5pdmVyc2FsY29kZS8jY29uZmlndXJhdGlvbi12YXJpYWJsZXMqLwovKgp2YXIgZGlzcXVzX2NvbmZpZyA9IGZ1bmN0aW9uICgpIHsKdGhpcy5wYWdlLnVybCA9IFBBR0VfVVJMOyAgLy8gUmVwbGFjZSBQQUdFX1VSTCB3aXRoIHlvdXIgcGFnZSdzIGNhbm9uaWNhbCBVUkwgdmFyaWFibGUKdGhpcy5wYWdlLmlkZW50aWZpZXIgPSBQQUdFX0lERU5USUZJRVI7IC8vIFJlcGxhY2UgUEFHRV9JREVOVElGSUVSIHdpdGggeW91ciBwYWdlJ3MgdW5pcXVlIGlkZW50aWZpZXIgdmFyaWFibGUKfTsKKi8KKGZ1bmN0aW9uKCkgeyAvLyBET04nVCBFRElUIEJFTE9XIFRISVMgTElORQp2YXIgZCA9IGRvY3VtZW50LCBzID0gZC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTsKcy5zcmMgPSAnaHR0cHM6Ly9odHRwcy1zYmFsY2ktZ2l0aHViLWlvLmRpc3F1cy5jb20vZW1iZWQuanMnOwpzLnNldEF0dHJpYnV0ZSgnZGF0YS10aW1lc3RhbXAnLCArbmV3IERhdGUoKSk7CihkLmhlYWQgfHwgZC5ib2R5KS5hcHBlbmRDaGlsZChzKTsKfSkoKTsKPC9zY3JpcHQ+Cjxub3NjcmlwdD5QbGVhc2UgZW5hYmxlIEphdmFTY3JpcHQgdG8gdmlldyB0aGUgPGEgaHJlZj0iaHR0cHM6Ly9kaXNxdXMuY29tLz9yZWZfbm9zY3JpcHQiPmNvbW1lbnRzIHBvd2VyZWQgYnkgRGlzcXVzLjwvYT48L25vc2NyaXB0PgoKLS0tCgojIMSwbGV0acWfaW0gIAoKQ29tcGxldGVkIG9uIGByIFN5cy5EYXRlKClgLiAgCgpTZXJkYXIgQmFsY2ksIE1ELCBQYXRob2xvZ2lzdCAgCmRyc2VyZGFyYmFsY2lAZ21haWwuY29tICAKCmh0dHBzOi8vcnB1YnMuY29tL3NiYWxjaS9DViAgIApodHRwczovL3NiYWxjaS5naXRodWIuaW8vICAKaHR0cHM6Ly9naXRodWIuY29tL3NiYWxjaSAgCmh0dHBzOi8vdHdpdHRlci5jb20vc2VyZGFyYmFsY2kKCgotLS0KCiAgIAoKCgotLS0KCgojIE90aGVyIExpbmtzCgoKaHR0cHM6Ly9hbmRyZXdidHJhbi5naXRodWIuaW8vTklDQVIvMjAxOC93b3JrZmxvdy9kb2NzLzAyLXJtYXJrZG93bi5odG1sCgotIFRyb3VibGVzaG9vdGluZyBpbiBSIE1hcmtkb3duCgpodHRwczovL3NtaXRoY29sbGVnZS1zZHMuZ2l0aHViLmlvL3Nkcy1wdWJsaWMvcm1hcmtkb3duX3Byb2JsZW1zLmh0bWwKCgpodHRwOi8va2Jyb21hbi5vcmcva25pdHJfa251dHNoZWxsL3BhZ2VzL1JtYXJrZG93bi5odG1sCgpodHRwczovL2ticm9tYW4ub3JnL2tuaXRyX2tudXRzaGVsbC9wYWdlcy9vdmVydmlldy5odG1sCgpodHRwczovL2ticm9tYW4ub3JnL2tuaXRyX2tudXRzaGVsbC9wYWdlcy9SbWFya2Rvd24uaHRtbAoKaHR0cHM6Ly9rYnJvbWFuLm9yZy9rbml0cl9rbnV0c2hlbGwvcGFnZXMvbWFya2Rvd24uaHRtbAoKCmh0dHBzOi8vb25wNC5jb20vCgoKCmBgYApjc3Yge2hlYWRlcnM6IHRydWUsIHRpdGxlOiAiKipEcmF3aW5nIFRhYmxlcyBJbiBNYXJrZG93bioqIn0KTmFtZSwgU3VybmFtZSwgS25vd24gQXMsIEFnZQpNYXJjZWxvLCBEYXZpZCwgY29sZHplcmEsIDIyCk9sZWtzYW5kciwgS29zdHlsaWV2LCBzMW1wbGUsIDE5Ck5pa29sYSwgS292YcSNLCBOaUtvLCAyMApSaWNoYXJkLCBQYXBpbGxvbiwgc2hveCwgMjUKTmljb2xhaSwgUmVlZHR6LCBkZXYxY2UsIDIxCmBgYAoKYGBgCntwZ259CltFdmVudCAiQmxlZC1aYWdyZWItQmVsZ3JhZGUgQ2FuZGlkYXRlcyJdCltTaXRlICJCbGVkLCBaYWdyZWIgJiBCZWxncmFkZSBZVUciXQpbRGF0ZSAiMTk1OS4xMC4xMSJdCltSb3VuZCAiMjAiXQpbUmVzdWx0ICIxLTAiXQpbV2hpdGUgIk1pa2hhaWwgVGFsIl0KW0JsYWNrICJSb2JlcnQgSmFtZXMgRmlzY2hlciJdCgoxLiBkNCBOZjYgMi4gYzQgZzYgMy4gTmMzIEJnNyA0LiBlNCBkNiA1LgpCZTIgTy1PIDYuIE5mMyBlNSA3LiBkNSBOYmQ3IDguIEJnNSBoNiA5LgpCaDQgYTYgMTAuIE8tTyBRZTggMTEuIE5kMiBOaDcgMTIuIGI0IEJmNgoxMy4gQnhmNiBOaHhmNiAxNC4gTmIzIFFlNyAxNS4gUWQyIEtoNyAxNi4KUWUzIE5nOCAxNy4gYzUgZjUgMTguIGV4ZjUgZ3hmNSAxOS4gZjQgZXhmNAoyMC4gUXhmNCBkeGM1IDIxLiBCZDMgY3hiNCAyMi4gUmFlMSBRZjYgMjMuClJlNiBReGMzIDI0LiBCeGY1KyBSeGY1IDI1LiBReGY1KyBLaDggMjYuClJmMyBRYjIgMjcuIFJlOCBOZjYgMjguIFF4ZjYrIFF4ZjYgMjkuIFJ4ZjYKS2c3IDMwLiBSZmY4IE5lNyAzMS4gTmE1IGg1IDMyLiBoNCBSYjggMzMuCk5jNCBiNSAzNC4gTmU1IDEtMApgYGAKCgotIEtlZXBpbmcgQ3JlZGVudGlhbHMgU2VjcmV0IHdpdGggS2V5cmluZ3MgaW4gUgoKaHR0cHM6Ly9yYXM0NC5naXRodWIuaW8vYmxvZy8yMDE5LzAxLzE5L2tlZXBpbmctY3JlZGVudGlhbHMtc2VjcmV0LXdpdGgta2V5cmluZ3MtaW4tci5odG1sCgotIEhvdyB0byBidWlsZCBhIHdlYnNpdGUgd2l0aCBCbG9nZG93biBpbiBSCgpodHRwOi8vd3d3LnN0b3J5YmVuY2gub3JnL2hvdy10by1idWlsZC1hLXdlYnNpdGUtd2l0aC1ibG9nZG93bi1pbi1yLwo=